#include "interpreter.h"
Interpreter::Interpreter(string input)
{
    input_file_name_ = input;
    fin_.open(input_file_name_);
    if (!fin_.is_open()) {
        cout << TAG << " Failed to open file " << input << endl;
    }
}

Interpreter::~Interpreter()
{
    if (fin_.is_open()) {
        fin_.close();
    }
    delete reg_pool_;
}

bool Interpreter::CheckAndResolve()
{
    string curr_line;
    fin_ >> curr_line;
    if (curr_line != FOREST_VERSION) {
        cout << TAG << "Check version failed. Runtime version is " << FOREST_VERSION <<
            ", version of file " << input_file_name_ << " is " << curr_line << endl;
        return false;
    }
    if (DEBUG) {
        cout << TAG << "Check version successful " << FOREST_VERSION << endl;
    }
    fin_ >> curr_line;
    int reg_num = atoi(curr_line.c_str());
    if (DEBUG) {
        cout << TAG << "Register number " << reg_num << endl;
    }
    reg_pool_ = new ValPool(reg_num);
    return true;
}

void Interpreter::Interpret()
{
    string op_code, target, source;
    int line_num = 0;
    while(fin_ >> op_code) {
        fin_ >> target;
        fin_ >> source;
        BYTE_CODE code = ByteCodeHelper::GetByteCodeByName(op_code);
        if (DEBUG) {
            cout << TAG << "current line " << line_num++ << ", code " << static_cast<int>(code) <<
                ", target " << target << ", source " << source << endl;
        }
        int target_pos= GetOpValue(target);
        int source_pos = GetOpValue(source);
        switch (code) {
            case BYTE_CODE::MOV_CON:
                reg_pool_->SetValue(target_pos, source_pos);
                break;
            case BYTE_CODE::MOV:
                reg_pool_->SetValue(target_pos, reg_pool_->GetValue(source_pos));
                break;
            case BYTE_CODE::ADD:
                reg_pool_->SetValue(target_pos, reg_pool_->GetValue(source_pos) + reg_pool_->GetValue(target_pos));
                break;
            case BYTE_CODE::MINUS:
                reg_pool_->SetValue(target_pos, reg_pool_->GetValue(target_pos) - reg_pool_->GetValue(source_pos));
                break;
            case BYTE_CODE::MUL:
                reg_pool_->SetValue(target_pos, reg_pool_->GetValue(target_pos) * reg_pool_->GetValue(source_pos));
                break;
            case BYTE_CODE::DIV:
                reg_pool_->SetValue(target_pos, reg_pool_->GetValue(target_pos) / reg_pool_->GetValue(source_pos));
                break;
            case BYTE_CODE::PRINT:
                cout << "Val in v" << target_pos << ": " << reg_pool_->GetValue(target_pos) << endl;
                break;
            default:
                break;
        }
        if (DEBUG) {
            reg_pool_->Print();
        }
    }
}